#pragma once
#include "../mqcommon/Log.hpp"
#include "../mqcommon/Helper.hpp"
#include "../mqcommon/Message.pb.h"

#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>

namespace ouyangmq
{
    // 交换机数据类
    struct Exchange
    {
        // 智能指针管理对象
        using ptr = std::shared_ptr<Exchange>;
        // 1. 交换机名称
        std::string name;
        // 2. 交换机类型
        ExchangeType type;
        // 3. 是否持久化标志
        bool durable;
        // 4. 是否自动删除标志
        bool auto_delete;
        // 5. 其他参数
        std::unordered_map<std::string, std::string> args;

        // 构造函数
        Exchange() {}
        Exchange(const std::string &ename, ExchangeType etype,
                 bool edurable, bool eauto_delete, std::unordered_map<std::string, std::string> eargs)
            : name(ename), type(etype), durable(edurable), auto_delete(eauto_delete), args(eargs)
        {
        }

        // args存储键对值，在存储数据库时，按照一个指定格式的字符串存储 key=val&key=val......
        // 内部解析str_args字符串，将内容存储到成员args中
        void SetArgs(const std::string &str_args)
        {
            std::vector<std::string> vargs;
            HelperModule::SplitHelper::split(str_args, "&", vargs);
            // key=val key=val ...
            for (int i = 0; i < vargs.size(); ++i)
            {
                std::string kv = vargs[i];
                int pos = kv.find('=');
                std::string key = kv.substr(0, pos);
                std::string value = kv.substr(pos + 1);
                args.emplace(key, value);
            }
        }

        // 将args中的内容进行序列化后返回一个字符串
        std::string GetArgs()
        {
            std::string ret;
            for (const auto &[a, b] : args)
            {
                ret += (a + "=" + b);
                ret += "&";
            }
            return ret;
        }
    };

    // 交换机数据持久化类 --> Exchange类.durable == true 才去进行数据持久化
    class ExchangeMapper
    {
    public:
        // 智能指针管理对象
        using ptr = std::shared_ptr<ExchangeMapper>;
        // 构造函数
        ExchangeMapper(const std::string &dbfile)
            : _sqlit_helper(dbfile)
        {
            // 创建指定目录
            HelperModule::FileHelper::Createfile(dbfile);
            // 打开对应的数据库文件
            assert(_sqlit_helper.open());
            // 创建表
            CreateTable();
        }

        // 1. 创建/删除交换机数据表
        void CreateTable()
        {
#define CREATE_TABLE "create table if not exists exchange_table(\
            name varchar(32) primary key, \
            type int, \
            durable int, \
            auto_delete int, \
            args varchar(128));"
            bool ret = _sqlit_helper.exec(CREATE_TABLE, nullptr, nullptr);
            if (ret == false)
            {
                LogModule::LOG(LogModule::LogLevel::ERROR) << "创建交换机数据库表失败";
                abort(); // 异常退出
            }
        }

        void DeleteTable()
        {
#define DEOP_TABLE "drop table if exists exchange_table;"
            bool ret = _sqlit_helper.exec(DEOP_TABLE, nullptr, nullptr);
            if (ret == false)
            {
                LogModule::LOG(LogModule::LogLevel::ERROR) << "删除交换机数据库表失败";
                abort(); // 异常退出
            }
        }

        // 2. 新增/移除交换机数据
        bool AddExchange(Exchange::ptr &exchange)
        {
            // "insert into exchange_table values('')"
            std::stringstream ss;
            ss << "insert into exchange_table values('"
               << exchange->name << "', " << exchange->type << ", "
               << exchange->durable << ", " << exchange->auto_delete << ", '"
               << exchange->GetArgs() << "');";
            return _sqlit_helper.exec(ss.str(), nullptr, nullptr);
        }

        void RemoveExchange(const std::string &name)
        {
            std::stringstream ss;
            ss << "delete from exchange_table where name=";
            ss << "'" << name << "';";
            _sqlit_helper.exec(ss.str(), nullptr, nullptr);
        }

        // 3. 查询所有交换机数据
        using ExchangeMap = std::unordered_map<std::string, Exchange::ptr>;
        ExchangeMap Recovery()
        {
            ExchangeMap result;
            std::string sql = "select name, type, durable, auto_delete, args from exchange_table";
            _sqlit_helper.exec(sql, ExchangeCallback, &result);
            return result;
        }

    private:
        // 必须使用static静态函数，不然参数列表中会含有this参数
        // typedef int (*SqliteCallback)(void *, int, char **, char **);
        static int ExchangeCallback(void *arg, int col, char **ret, char **fields)
        {
            ExchangeMap *result = static_cast<ExchangeMap *>(arg);
            Exchange::ptr ep = std::make_shared<Exchange>();
            ep->name = ret[0];
            ep->type = (ouyangmq::ExchangeType)std::stoi(ret[1]);
            ep->durable = (bool)std::stoi(ret[2]);
            ep->auto_delete = (bool)std::stoi(ret[3]);
            // 如果其他参数存在(查看是否为nullptr)
            // std::unordered_map<std::string, std::string> args;
            if (ret[4])
                ep->SetArgs(ret[4]);
            result->emplace(ep->name, ep);
            return 0; // 必须返回
        }
        // 1. sqlit数据库操作句柄
        HelperModule::SqliteHelper _sqlit_helper;
    };

    // 交换机数据管理类
    class ExchangeManager
    {
    public:
        // 智能指针管理对象
        using ptr = std::shared_ptr<ExchangeManager>;
        // 构造函数
        ExchangeManager(const std::string &dbfile)
            : _mapper(dbfile)
        {
            // 加载持久化的交换机数据
            _exchanges = _mapper.Recovery();
        }

        // 1. 声明/删除交换机
        bool DeclareExchange(const std::string &name, ExchangeType type,
                             bool durable, bool auto_delete, std::unordered_map<std::string, std::string> &args)
        {
            // 加锁
            std::unique_lock<std::mutex> lock(_mutex);
            {
                auto it = _exchanges.find(name);
                if (it != _exchanges.end())
                {
                    // 交换机已经存在不用新增
                    return true;
                }
                Exchange::ptr ep = std::make_shared<Exchange>(name, type, durable, auto_delete, args);
                // 如果持久化标志为true
                if (ep->durable == true)
                {
                    bool ret = _mapper.AddExchange(ep);
                    if(ret == false) return ret;
                }
                _exchanges.emplace(name, ep);
                return true;
            }
        }

        void DeleteExchange(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            {
                // 交换机不存在直接返回
                auto it = _exchanges.find(name);
                if (it == _exchanges.end())
                    return;
                if (it->second->durable == true)
                    _mapper.RemoveExchange(name); // 如果是持久化存储的再去表中删除
                _exchanges.erase(name);
            }
        }

        // 2. 获取指定交换机
        Exchange::ptr GetOneExchage(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            {
                // 交换机不存在直接返回控对象
                auto it = _exchanges.find(name);
                if (it == _exchanges.end())
                    return Exchange::ptr();
                return it->second;
            }
        }

        // 3. 销毁所有交换机数据
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            {
                _mapper.DeleteTable();
                _exchanges.clear();
            }
        }

        // 4. 指定交换机是否存在
        bool Exists(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            {
                auto it = _exchanges.find(name);
                if (it == _exchanges.end())
                {
                    return false;
                }
                return true;
            }
        }

        size_t Size()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _exchanges.size();
        }

    private:
        std::mutex _mutex;
        ExchangeMapper _mapper;
        std::unordered_map<std::string, Exchange::ptr> _exchanges;
    };

}